package com.example.usercenter.precache;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.example.usercenter.model.domain.User;
import com.example.usercenter.service.UserService;
import com.google.gson.Gson;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.example.usercenter.constants.UserConstant.*;

/**
 * 缓存预热定时器
 * @author 米饭好好吃
 */
@Component
@Slf4j
public class PreCache {

    @Resource
    private UserService userService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Resource
    private RedissonClient redissonClient;

    @Scheduled(cron = "0 50 23 * * ?") // 设置cron表达式
    public void preCache() {
        Gson gson = new Gson();
        // 0. 获取redisson锁对象
        RLock rLock = redissonClient.getLock(REDISSON_KEY);
        try {
            boolean lockRes = rLock.tryLock(-1, 30, TimeUnit.SECONDS);
            // 0.1 如果抢到锁就执行缓存预热逻辑
            if (lockRes) {
                log.info("开始缓存预热...");
                // 1. 提前预热页名单
                List<Integer> preCacheIdList = PRE_CACHE_ID_LIST;
                // 2. 遍历列表，先从数据库查询然后进行缓存
                for (int preCacheId : preCacheIdList) {
                    List<User> dbUserList = userService.page(new Page<>(1, 20)).getRecords();
                    List<User> safetyUserList = dbUserList
                            .stream()
                            .map(dbUser -> userService.getSafetyUser(dbUser))
                            .collect(Collectors.toList());
                    String cacheUserKey = USER_KEY_PREFIX + preCacheId;
                    String safetyUserListStr = gson.toJson(safetyUserList);
                    redisTemplate.opsForValue().set(cacheUserKey, safetyUserListStr, USER_EXPIRES_TIME, TimeUnit.MINUTES);
                }
            }
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        } finally {
            if (rLock.isHeldByCurrentThread()) {
                // 如果锁是当前线程持有的才进行删除
                rLock.unlock();
            }
        }

    }
}
